#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <string>
#include <iomanip>

#include "shekel_function.h"
#include "griewank_function.h"
#include "rosenbrock_function.h"
#include "zakharov_function.h"

#include "continuous_tabusearch.h"
#include "Time.h"
#include "wrapperFunctions.h"
#include "dash_simplex.h"

#define PI   3.1415926535897932385

using namespace std;

void run_Simp(int argc, char *argv[ ], Function *func, string& directory, int numDim)
{
  int seed = -1000;                 // seed for random number

  initiate_ran1(seed);      // initiates the random number

  Time timer;               // to measure calculation times
  cout << "prepare timer " << timer;

  double *sol;              // the solutions we will follow



  ////////////////////////////////////////////////////////////////
  // Open files CGM_Solution.out and CGM_initial_values.out,
  // and prepare them for output. CGM_Solution.out holds the
  // best function value after each run both without local
  // minimisation and with local minimisation. CGM_initial_values
  // holds the initial coordinates (debugging).
  ////////////////////////////////////////////////////////////////

  ofstream outEndSimp_Solution( string(directory + "Simp_Solution.out").c_str());

  outEndSimp_Solution << "Dimension: " << numDim << endl
    << "Smallest function value after each run\n\n"
    << "      Func Val Bef     Func Val After      Function Evaluations      Distance       Run Number" << endl << endl;

  ofstream outIniVal("output/Simp_initial_values.out");

  Function *function;       // Creates an instance of the function
  function = func;          // Sets the function = to the function passed as an argument

  newA(sol, numDim);

  cout << "Time: " << timer;

	for(int i=1; i<=10; i++)  
	{
    cout << "Run No. " << i << endl;

    // Populate the Input array which a random start position/configuration
    function->nCall=0;
		function->createRandomSol(sol);

    // Print out the run number and initial
    // starting configuration (coordinates)
		outIniVal << "\nRun No. " << i << endl << endl;
    outIniVal << "Variable | Starting values" << endl;
		for (int k=1; k<=numDim; k++)
    {
      outIniVal << setw(5) << k << setw(18) << sol[k] << endl;
    }

    // reset tracker before starting a new CTS run (in run_test.h)
		//ResetTracker(sol, function);            // calculates the function value of sol

    double origValue = function->Value(sol);

    // print out best solution (before local minimisation)
		char resultSimp[80];
		/*sprintf_s(resultSimp, 40, string(directory + "result_Simp%d.txt").c_str(), i);
    function->print_sol(sol, origValue, resultSimp);*/

    outEndSimp_Solution << setw(16) << origValue;

    // calls simplex function
    //wrapperSimplex(sol, numDim, 1e-20, 0.1, origValue, function);  
    //wrapperDoshSimplex(sol, 0.1, numDim, origValue, function);
    //dashSimplex(sol, 0.1, numDim, origValue, function);


		sprintf_s(resultSimp, 80, string(directory + "Simp_result_Simp%d.txt").c_str(), i);
		function->print_sol(sol, origValue, resultSimp, 0, 0);

    // after local minimisation lBestFuncValue has been changed
    // this sets lBestFuncValue equal to bestFuncValue which is
    // then outputted
	  outEndSimp_Solution << setw(18) << origValue << setw(23) << function->nCall << setw(19)
      << function->distanceFromGlobalMinimum(sol) << setw(14) << i << endl;
  }

  outEndSimp_Solution << "\nGlobal best value over all runs:\t" << setw(9) << function->BestSoFar() << endl;

  outEndSimp_Solution.close();
  outIniVal.close();

  // print final output to screen
  cout << endl << endl << "Output files have been written to " << directory << endl;
  cout << "The total time for the simulation was " << timer << endl << endl;
  cout << "---------------------------" << endl << endl;
}

/*void ResetTracker(double *I, Function *func)
{
  double x;

  x = func->Value(I);

  func->Result.ResetWith(x,I);
}*/